/*
 * serialComm_impl.c
 *
 *  Created on: Apr 25, 2021
 *      Author: taoyu
 */

#include <stdint.h>
#include "serialComm_cfg.h"
#include "serialComm_api.h"
#include "serialComm_port.h"

typedef enum
{
	TX_STATE_INIT = 0,
	TX_STATE_IDLE,
	TX_STATE_BUSY,
}
TX_STATE;

typedef enum
{
	RX_STATE_INIT = 0,
	RX_STATE_IDLE,
	RX_STATE_BUSY,
	RX_STATE_READY,
	RX_STATE_OVERFLOW,
}
RX_STATE;

typedef struct
{
	// tx
	TX_STATE txState;
	uint8_t txBuffer[SERIAL_COMM_BUFFER_SIZE];
	uint8_t txLength;
	uint8_t txCount;

	// rx
	RX_STATE rxState;
	uint8_t rxBuffer[SERIAL_COMM_BUFFER_SIZE];
	uint8_t rxCount;
	uint8_t rxLength;
	uint8_t rxOverflowCount;
}
SERIAL_COMM_DATA;

SERIAL_COMM_DATA	serialComm_Data[SERIAL_COMM_CHANNEL_TOTAL_NUMBERS];

void serialComm_pport_init(SERIAL_COMM_CHANNEL channel)
{
	serialComm_Data[channel].txState = TX_STATE_IDLE;
	serialComm_Data[channel].rxState = RX_STATE_IDLE;
	serialComm_Data[channel].rxOverflowCount = 0;
}

#ifdef  SERIAL_COMM_VERIFY_INTEGRATION
static void serialComm_verifyIntegration(void)
{
#if SERIAL_COMM_VERIFY_INTEGRATION==1
	/// cyclically send out the fixed data "UVW"
	static uint8_t buffer[4] = "UVW";
	static uint8_t cnt = 0;
	if(cnt==0) serialComm_send(0,buffer,sizeof(buffer));
	cnt++;
#endif

#if SERIAL_COMM_VERIFY_INTEGRATION==2
	/// send what received at once
	static uint8_t buffer[SERIAL_COMM_BUFFER_SIZE];
	int br = serialComm_receive(0,buffer,sizeof(buffer));
	if(br>0) serialComm_send(0,buffer,br);
#endif
}
#endif

void serialComm_pport_task1ms(SERIAL_COMM_CHANNEL channel)
{
#ifdef  SERIAL_COMM_VERIFY_INTEGRATION
	serialComm_verifyIntegration();
#endif
}

int serialComm_send(SERIAL_COMM_CHANNEL channel, uint8_t * buffer, int length)
{
	uint8_t i;

	/* check arguments */
	if( channel>=SERIAL_COMM_CHANNEL_TOTAL_NUMBERS ) return -1;
	if( !buffer ) return -2;
	if( !length ) return -3;

	/* check data length and buffer size */
	if( length>sizeof(serialComm_Data[channel].txBuffer) ) return -4;

	/* check tx state */
	if( serialComm_Data[channel].txState != TX_STATE_IDLE ) return -5;

	/* copy data */
	for(i=0;i<length;i++) serialComm_Data[channel].txBuffer[i] = buffer[i];
	serialComm_Data[channel].txLength = length;

	/* start send */
	serialComm_Data[channel].txCount = 0;
	serialComm_Data[channel].txState = TX_STATE_BUSY;
	serialComm_rport_startSend(channel);

	/* started */
	return length;
}

int serialComm_ISR_sendBufferEmpty(SERIAL_COMM_CHANNEL channel)
{
	int ret = 0;

	// check state
	if( serialComm_Data[channel].txState == TX_STATE_BUSY )
	{
		// check end
		if( serialComm_Data[channel].txCount < serialComm_Data[channel].txLength )
		{
			// send the data
			serialComm_rport_sendData(channel, serialComm_Data[channel].txBuffer[serialComm_Data[channel].txCount]);
			// next
			serialComm_Data[channel].txCount ++;
		}
		else
		{
			ret = -2;
		}
	}
	else
	{
		ret = -1;
	}

	// if no next data, stop send, back to idle
	if( ret<0 )
	{
		serialComm_rport_stopSend(channel);
		serialComm_Data[channel].txState = TX_STATE_IDLE;
	}

	return ret;
}

int serialComm_ISR_dataByteReceived(SERIAL_COMM_CHANNEL channel, uint8_t data)
{
	int ret = 0;

	switch( serialComm_Data[channel].rxState )
	{
	case	RX_STATE_IDLE:
		// this is the first data
		serialComm_Data[channel].rxBuffer[0] = data;
		serialComm_Data[channel].rxCount = 1;
		// change state to busy
		serialComm_Data[channel].rxState = RX_STATE_BUSY;
		// reset overflow counter
		serialComm_Data[channel].rxOverflowCount = 0;
		break;
	case	RX_STATE_BUSY:
		// store the data
		if(serialComm_Data[channel].rxCount < sizeof(serialComm_Data[channel].rxBuffer))
		{
			// store the data
			serialComm_Data[channel].rxBuffer[serialComm_Data[channel].rxCount] = data;
			serialComm_Data[channel].rxCount++;
			// keep busy
		}
		else
		{
			// overflow
			serialComm_Data[channel].rxState = RX_STATE_OVERFLOW;
			ret = -1;
		}
		break;
	case	RX_STATE_READY:
		// should never happen
		ret = -1;
		break;
	case	RX_STATE_OVERFLOW:
		// ignore the data
		// keep overflow
		// count overflow
		if(serialComm_Data[channel].rxOverflowCount<0xff)
		{
			serialComm_Data[channel].rxOverflowCount++;
		}
		ret = -1;
		break;
	default:
		ret = -1;
		break;
	}

	return ret;
}

int serialComm_ISR_busIdleDetected(SERIAL_COMM_CHANNEL channel)
{
	int ret = 0;

	switch( serialComm_Data[channel].rxState )
	{
	case RX_STATE_IDLE:
		// should never happens
		ret = -1;
		break;
	case RX_STATE_BUSY:
		// message finished
		serialComm_Data[channel].rxState = RX_STATE_READY;
		serialComm_Data[channel].rxLength = serialComm_Data[channel].rxCount;
		break;
	case RX_STATE_READY:
		// should never happens
		ret = -1;
		break;
	case RX_STATE_OVERFLOW:
		// directly back to idle
		serialComm_Data[channel].rxState = RX_STATE_IDLE;
		break;
	default:
		// directly back to idle
		serialComm_Data[channel].rxState = RX_STATE_IDLE;
		ret = -1;
		break;
	}

	return ret;
}

int serialComm_receive(SERIAL_COMM_CHANNEL channel, uint8_t * buffer, int length)
{
	int ret = 0;

	if( serialComm_Data[channel].rxState==RX_STATE_READY )
	{
		// check buffer length
		if( serialComm_Data[channel].rxLength <= length )
		{
			uint8_t i;
			// copy data
			for(i=0;i<serialComm_Data[channel].rxLength;i++) buffer[i] = serialComm_Data[channel].rxBuffer[i];
			ret = i;
		}
		else
		{
			// user buffer not enough
			ret = -1;
		}

		// release rx buffer
		serialComm_Data[channel].rxState = RX_STATE_IDLE;
	}
	else
	{
		// no package received
		ret = 0;
	}

	return ret;
}

